package com.bjpowernode.micrpaykq.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bjpowernode.api.service.RechargeService;
import com.bjpowernode.contacts.RedisKey;
import com.bjpowernode.micrpaykq.util.HttpUtil;
import com.bjpowernode.micrpaykq.util.OrderIdUtil;
import com.bjpowernode.micrpaykq.util.Pkipair;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * ClassName:KuaiQianService
 * Date:2022/1/4 11:52
 */
@Service
public class KQService {

    @Autowired
    private OrderIdUtil orderIdUtil;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference(interfaceClass = RechargeService.class,version = "1.0")
    private RechargeService rechargeService;

    //生成快钱接口需要的数据
    //返回值Map就是提交给快钱的参数的集合
    public Map<String,String> generateFormData(Integer userId,BigDecimal money, String phone,String token){

        Map<String,String> params = new HashMap<>();
        //人民币网关账号，该账号为11位人民币网关商户编号+01,该参数必填。
        String merchantAcctId = "1001214035601";
        //编码方式，1代表 UTF-8; 2 代表 GBK; 3代表 GB2312 默认为1,该参数必填。
        String inputCharset = "1";
        //接收支付结果的页面地址，该参数一般置为空即可。
        String pageUrl = "";
        //服务器接收支付结果的后台地址，该参数务必填写，不能为空。
        String bgUrl = "http://123.249.17.208:9000/pay/receive/kq/notify";
        //网关版本，固定值：v2.0,该参数必填。
        String version =  "v2.0";
        //语言种类，1代表中文显示，2代表英文显示。默认为1,该参数必填。
        String language =  "1";
        //签名类型,该值为4，代表PKI加密方式,该参数必填。
        String signType =  "4";
        //支付人姓名,可以为空。
        String payerName= "";
        //支付人联系类型，1 代表电子邮件方式；2 代表手机联系方式。可以为空。
        String payerContactType =  "2";
        //支付人联系方式，与payerContactType设置对应，payerContactType为1，则填写邮箱地址；payerContactType为2，则填写手机号码。可以为空。
        String payerContact = phone;
        //指定付款人，可以为空 ,
        String payerIdType =  "3";
        //付款人标识，可以为空, 盈利宝平台的userId
        String payerId =  String.valueOf(userId);
        //付款人IP，可以为空
        String payerIP =  "";

        //商户订单号，以下采用时间来定义订单号，商户可以根据自己订单号的定义规则来定义该值，不能为空。
        String orderId = generateKqOrderId();

        //订单金额，金额以“分”为单位，商户测试以1分测试即可，切勿以大金额测试。该参数必填。
        String orderAmount = money.multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString();

        //订单提交时间，格式：yyyyMMddHHmmss，如：20071117020101，不能为空。
        String orderTime = new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
        //快钱时间戳，格式：yyyyMMddHHmmss，如：20071117020101， 可以为空
        String orderTimestamp= new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());;
        //商品名称，可以为空。
        String productName= "理财充值";
        //商品数量，可以为空。
        String productNum = "1";
        //商品代码，可以为空。
        String productId = "10000";
        //商品描述，可以为空。
        String productDesc = "动力理财产品";
        //扩展字段1，商户可以传递自己需要的参数，支付完快钱会原值返回，可以为空。
        String ext1 = String.valueOf(userId);
        //扩展自段2，商户可以传递自己需要的参数，支付完快钱会原值返回，可以为空。
        String ext2 = token;
        //支付方式，一般为00，代表所有的支付方式。如果是银行直连商户，该值为10-1或10-2，必填。
        String payType = "00";
        //银行代码，如果payType为00，该值可以为空；如果payType为10-1或10-2，该值必须填写，具体请参考银行列表。
        String bankId = "";
        //同一订单禁止重复提交标志，实物购物车填1，虚拟产品用0。1代表只能提交一次，0代表在支付不成功情况下可以再提交。可为空。
        String redoFlag = "0";
        //快钱合作伙伴的帐户号，即商户编号，可为空。
        String pid = "";

        // signMsg 签名字符串 不可空，生成加密签名串
        String signMsgVal = "";
        signMsgVal = appendParam(signMsgVal, "inputCharset", inputCharset,params);
        signMsgVal = appendParam(signMsgVal, "pageUrl", pageUrl,params);
        signMsgVal = appendParam(signMsgVal, "bgUrl", bgUrl,params);
        signMsgVal = appendParam(signMsgVal, "version", version,params);
        signMsgVal = appendParam(signMsgVal, "language", language,params);
        signMsgVal = appendParam(signMsgVal, "signType", signType,params);
        signMsgVal = appendParam(signMsgVal, "merchantAcctId",merchantAcctId,params);
        signMsgVal = appendParam(signMsgVal, "payerName", payerName,params);
        signMsgVal = appendParam(signMsgVal, "payerContactType",payerContactType,params);
        signMsgVal = appendParam(signMsgVal, "payerContact", payerContact,params);
        signMsgVal = appendParam(signMsgVal, "payerIdType", payerIdType,params);
        signMsgVal = appendParam(signMsgVal, "payerId", payerId,params);
        signMsgVal = appendParam(signMsgVal, "payerIP", payerIP,params);
        signMsgVal = appendParam(signMsgVal, "orderId", orderId,params);
        signMsgVal = appendParam(signMsgVal, "orderAmount", orderAmount,params);
        signMsgVal = appendParam(signMsgVal, "orderTime", orderTime,params);
        signMsgVal = appendParam(signMsgVal, "orderTimestamp", orderTimestamp,params);
        signMsgVal = appendParam(signMsgVal, "productName", productName,params);
        signMsgVal = appendParam(signMsgVal, "productNum", productNum,params);
        signMsgVal = appendParam(signMsgVal, "productId", productId,params);
        signMsgVal = appendParam(signMsgVal, "productDesc", productDesc,params);
        signMsgVal = appendParam(signMsgVal, "ext1", ext1,params);
        signMsgVal = appendParam(signMsgVal, "ext2", ext2,params);
        signMsgVal = appendParam(signMsgVal, "payType", payType,params);
        signMsgVal = appendParam(signMsgVal, "bankId", bankId,params);
        signMsgVal = appendParam(signMsgVal, "redoFlag", redoFlag,params);
        signMsgVal = appendParam(signMsgVal, "pid", pid,params);

        System.out.println(signMsgVal);
        Pkipair pki = new Pkipair();
        String signMsg = pki.signMsg(signMsgVal);

        //别忘了， signMsg
        params.put("signMsg",signMsg);

        return params;
    }

    /*处理快钱充值结果*/
    public void doKqNotify(HttpServletRequest request){
        String merchantAcctId = request.getParameter("merchantAcctId");
        String version = request.getParameter("version");
        String language = request.getParameter("language");
        String signType = request.getParameter("signType");
        String payType = request.getParameter("payType");
        String bankId = request.getParameter("bankId");
        String orderId = request.getParameter("orderId");
        String orderTime = request.getParameter("orderTime");
        String orderAmount = request.getParameter("orderAmount");
        String bindCard = request.getParameter("bindCard");
        if(request.getParameter("bindCard")!=null){
            bindCard = request.getParameter("bindCard");}
        String bindMobile="";
        if(request.getParameter("bindMobile")!=null){
            bindMobile = request.getParameter("bindMobile");}
        String bankDealId = request.getParameter("bankDealId");
        String dealTime = request.getParameter("dealTime");
        String payAmount = request.getParameter("payAmount");
        String fee = request.getParameter("fee");
        String ext1 = request.getParameter("ext1");
        String ext2 = request.getParameter("ext2");
        String payResult = request.getParameter("payResult");
        String aggregatePay = request.getParameter("aggregatePay");
        String errCode = request.getParameter("errCode");
        String signMsg = request.getParameter("signMsg");
        String dealId = request.getParameter("dealId");
        String merchantSignMsgVal = "";
        merchantSignMsgVal = appendParam(merchantSignMsgVal,"merchantAcctId", merchantAcctId,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "version",version,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "language",language,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "signType",signType,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "payType",payType,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "bankId",bankId,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "orderId",orderId,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "orderTime",orderTime,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "orderAmount",orderAmount,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "bindCard",bindCard,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "bindMobile",bindMobile,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "dealId",dealId,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "bankDealId",bankDealId,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "dealTime",dealTime,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "payAmount",payAmount,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "fee", fee,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "ext1", ext1,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "ext2", ext2,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "payResult",payResult,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "aggregatePay",aggregatePay,null);
        merchantSignMsgVal = appendParam(merchantSignMsgVal, "errCode",errCode,null);


        Pkipair pki = new Pkipair();
        //验签方法 TRUE:通过，false不能处理业务
        boolean flag = pki.enCodeByCer(merchantSignMsgVal, signMsg);
        System.out.println("flag====="+flag);

        if(flag){
            //验签通过
            //检查订单是否是商家自己的，比较merchantAcctId
            if( "1001214035601".equals(merchantAcctId)){
                //处理订单，调用data-service的方法
                rechargeService.handlerRecharge("kq",orderId,payResult,payAmount);
                System.out.println("通过验签的订单："+orderId);
            }
        } else {
            //没有通过
            //输出日志：
            System.out.println("没有通过验签的订单："+orderId+"|"+payAmount);
        }
    }

    /*把请求的参数连接为一个字符串格式：  参数名=值&参数名=值....*/
    private String appendParam(String returns, String paramId, String paramValue
                                  ,Map<String,String> params) {
        if (returns != "") {
            if (paramValue != "" && paramValue != null) {
                returns += "&" + paramId + "=" + paramValue;
                if( params != null){
                    params.put(paramId,paramValue);
                }
            }

        } else {

            if (paramValue != "" && paramValue != null ) {
                returns = paramId + "=" + paramValue;
                if( params != null){
                    params.put(paramId,paramValue);
                }
            }
        }

        return returns;
    }

    /*生成商家订单号*/
    public String generateKqOrderId(){
        /**
         * 订单号不重复
         * 1. 生成一个不重复的唯一值， 使用redis， incr命令。
         * 2. 生成随机数， 4或者6位的
         */
     long id =  orderIdUtil.generateId("orderId");
     String orderId = String.valueOf(id);
     return "KQ"+orderId;
    }


    //执行调用快钱查询接口，查询订单充值结果
    public void doKqQueryOrder(Set<String> orderIds) {
        //1.调用快钱的查询接口
        orderIds.forEach( orderId ->{
            String response =  invokeKqQuery(orderId);
            //2.根据快钱的查询结果，处理订单记录
            doQueryResult(response);
            //删除已经处理的orderId
            stringRedisTemplate.opsForZSet().remove(RedisKey.RECHARGE_ORDERID_LIST,orderId);
        });
    }
    
    private void doQueryResult(String response){
        if(StringUtils.isNotBlank(response)){
            //把response-json
            JSONObject object = JSONObject.parseObject(response);
            Object detailObject = object.get("orderDetail");
            if( detailObject != null){
                //有订单查询结果
                JSONArray array = (JSONArray)detailObject;
                JSONObject detail = (JSONObject)array.get(0);
                rechargeService.handlerRecharge("kq",detail.getString("orderId"),
                                           detail.getString("payResult"),
                                           detail.getString("payAmount"));
            }
        }
    }

    private String invokeKqQuery(String queryOrderId){
        Map<String, Object> request = new HashMap<String, Object>();
        //固定值：1代表UTF-8;
        String inputCharset = "1";
        //固定值：v2.0 必填
        String version = "v2.0";
        //1代表Md5，2 代表PKI加密方式  必填
        String signType = "2";
        //人民币账号 membcode+01  必填
        String merchantAcctId = "1001214035601";
        //固定值：0 按商户订单号单笔查询，1 按交易结束时间批量查询必填
        String queryType = "0";
        //固定值：1	代表简单查询 必填
        String queryMode = "1";
        String startTime = "";
        String endTime = "";
        String requestPage = "";
        String orderId = queryOrderId;
        String key = "27YKWKBKHT2IZSQ4";

        request.put("inputCharset", inputCharset);
        request.put("version", version);
        request.put("signType", signType);
        request.put("merchantAcctId", merchantAcctId);
        request.put("queryType", queryType);
        request.put("queryMode", queryMode);
        request.put("startTime", startTime);
        request.put("endTime", endTime);
        request.put("requestPage", requestPage);
        request.put("orderId", orderId);

        String message="";
        message = appendParam(message,"inputCharset",inputCharset,null);
        message = appendParam(message,"version",version,null);
        message = appendParam(message,"signType",signType,null);
        message = appendParam(message,"merchantAcctId",merchantAcctId,null);
        message = appendParam(message,"queryType",queryType,null);
        message = appendParam(message,"queryMode",queryMode,null);
        message = appendParam(message,"startTime",startTime,null);
        message = appendParam(message,"endTime",endTime,null);
        message = appendParam(message,"requestPage",requestPage,null);
        message = appendParam(message,"orderId",orderId,null);
        message = appendParam(message,"key",key,null);

        Pkipair pki = new Pkipair();
        String sign = pki.signMsg(message);
        //把生成的签名串也的放到map
        request.put("signMsg", sign);

        //sandbox提交地址
        String reqUrl = "https://sandbox.99bill.com/gatewayapi/gatewayOrderQuery.do";
        String response = "";
        try {
            response = HttpUtil.doPostJsonRequestByHttps(JSON.toJSONString(request), reqUrl, 3000, 8000);

        }catch (Exception e){
            e.printStackTrace();
        }
        return response;
    }
}
